package com.cyx.fruit.mySSM.IOC;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class ClassPathXmlApplicationContext implements BeanFactory{
    Map<String,Object> beanMap = new HashMap();    //ben容器，获取bena对象
    @Override
    public Object getBean(String id) {
        return beanMap.get(id);
    }

    /**
     * 解析xml文件 -- 根据XX.do来获取对应的实例化对象
     * 对实例化对象的属性赋值
     */
    public ClassPathXmlApplicationContext(){
        try {
            //获取applicationContext的文件输入流
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
            //获取DocumentBuilderFactory对象
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            //获取DocumentBuilder对象
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            //获取Document对象
            Document document = documentBuilder.parse(inputStream);
            //获取当前bean节点的Node列表
            NodeList beanList = document.getElementsByTagName("bean");

            for(int i = 0;i < beanList.getLength();i++){
                Node beanNode = beanList.item(i); // 获取当前的节点对象
                //beanNode是一个元素节点
                if(beanNode.getNodeType() == Node.ELEMENT_NODE){
                    //转为元素节点
                    Element benaElement = (Element) beanNode;
                    String beanId = benaElement.getAttribute("id");
                    String beanClassString = benaElement.getAttribute("class"); //全类名

                    //通过全类名进行反射，获取Class的对象
                    Class benaClass = Class.forName(beanClassString);
                    //通过Class类的对象获取实例对象
                    Object beanObj= benaClass.newInstance();   //new FruitController()

                    //将结果保存到map中
                    beanMap.put(beanId,beanObj);
                }
            }
            //组装bean之间的依赖关系，实现property标签 name=属性名称  ref=实例化对象的id名称
            for(int i = 0;i< beanList.getLength();i++){
                Node beanNode = beanList.item(i); //获取Node节点
                if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element beanElement = (Element) beanNode;     //转为元素对象
                    String beanId = beanElement.getAttribute("id"); //获取当前元素的id属性值

                    //获取当前元素的子节点列表
                    NodeList childNodeList = beanElement.getChildNodes();
                    for (int j = 0;j < childNodeList.getLength();j++){
                        Node childBeanNode = childNodeList.item(j);
                        if(childBeanNode.getNodeType() == Node.ELEMENT_NODE && childBeanNode.getNodeName().equals("property")){
                            Element childBeanElement = (Element) childBeanNode;

                            String propertyName = childBeanElement.getAttribute("name");
                            String propertyRef = childBeanElement.getAttribute("ref");

                            Object refObj = beanMap.get(propertyRef);   //；获取ref所对应的实例化对象

                            //将refObj对象注入到指定的属性中
                            Object beanObj = beanMap.get(beanId); //获取property标签的父标签id所对应的实例化对象
                            Field propertyField = beanObj.getClass().getDeclaredField(propertyName); //获取当前对象的File属性
                            propertyField.setAccessible(true);
                            propertyField.set(beanObj,refObj);
                        }
                    }
                }
            }


        } catch (ParserConfigurationException | SAXException | IOException | ClassNotFoundException |
                 InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }
}
